﻿using Scala.Compiler.Binding;
using Scala.Compiler.Types;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Text;
using System.Threading.Tasks;

namespace Scala.Compiler.Ast
{
    public class NameExpression : Expression
    {
        private readonly string _name;

        public NameExpression(string name)
        {
            _name = name;
        }

        public string Name { get { return _name; } }
        public ScalaType ScalaType { get; set; }
        public bool IsVar { get; set; }
        public bool IsFunc { get; set; }
        public bool IsType { get; set; }
        public Microsoft.Scripting.Ast.Expression Ret { get; set; }
        public PropertyBuilder PropInfo { get; set; }
        
        public override void Walk(ScalaWalker walker)
        {
            if (walker.Walk(this)) { }
            walker.PostWalk(this);
        }

        public override Microsoft.Scripting.Ast.Expression Reduce()
        {
            Type paramType;
            InternalTypes.GetType(TypeName,Scope,out paramType);
            ScalaVariable variable;
            ScalaFunction func;
            ScalaType scType;

            if (Scope.TryGetAnyVariable(Name, out variable))
            {
                Ret =  variable.ParamExpression;
                if (variable.IsProperty)
                {
                    PropInfo = variable.PropertyBuilder;
                }
                return Ret;
            }
            else if (Scope.TryGetAnyFunc(Name, out func))
            {
                if (!func.IsConstructor)
                {
                    if (func.ParamTypes.Length > 0 || func.ParamTypes != null)
                    {
                        Ret =  Expression.TypeMethodCall(
                                            func.MethodBuilder.DeclaringType,
                                            func.MethodBuilder,
                                            Type.EmptyTypes,
                                            null
                            );
                        return Ret;
                    }
                    else
                    {
                        throw new Exception(String.Format("Function {0} not called properly", func.Name));
                    }
                }
                else
                {
                    throw new Exception(String.Format("Constructor called as a function inf the type {0}", Name));
                }
            }
            else if (Scope.TryGetAnyType(Name, out scType))
            {
                IsType = true;
                ScalaType = scType;
                return Expression.Empty();
            }
            else
            {
                throw new Exception(String.Format("Undefined value {0} in the Scope {1}", Name, Scope.Name));
            }
        }
    }
}
